//
// Created by root on 4/29/17.
//

#include "../runner.h"

// (and #t #t) => #t
static void test_op_and_case1() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);
    EVAL_CODE_AND_RETURN(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #t #f) => #f
static void test_op_and_case2() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(G_TRUE, G_FALSE);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);
    EVAL_CODE_AND_RETURN(G_FALSE, G_FALSE);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #f #t) => #f
static void test_op_and_case3() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(G_FALSE, G_TRUE);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (and #f #f) => #f
static void test_op_and_case4() {
    global_scheme->op = cell_op_and0;
    global_scheme->code = LIST_2(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(and0);
    op_and0(global_scheme);
    EVAL_CODE_AND_RETURN(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(and1);
    op_and1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (or #t #t) => #t
static void test_op_or_case1() {
    global_scheme->op = cell_op_or0;
    global_scheme->code = LIST_2(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(or0);
    op_or0(global_scheme);
    EVAL_CODE_AND_RETURN(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (or #t #f) => #t
static void test_op_or_case2() {
    global_scheme->op = cell_op_or0;
    global_scheme->code = LIST_2(G_TRUE, G_FALSE);

    ASSERT_OP_CURRENT(or0);
    op_or0(global_scheme);
    EVAL_CODE_AND_RETURN(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (or #f #t) => #t
static void test_op_or_case3() {
    global_scheme->op = cell_op_or0;
    global_scheme->code = LIST_2(G_FALSE, G_TRUE);

    ASSERT_OP_CURRENT(or0);
    op_or0(global_scheme);
    EVAL_CODE_AND_RETURN(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);
    EVAL_CODE_AND_RETURN(G_TRUE, G_TRUE);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

// (or #f #f) => #f
static void test_op_or_case4() {
    global_scheme->op = cell_op_or0;
    global_scheme->code = LIST_2(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(or0);
    op_or0(global_scheme);
    EVAL_CODE_AND_RETURN(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);
    EVAL_CODE_AND_RETURN(G_FALSE, G_FALSE);

    ASSERT_OP_CURRENT(or1);
    op_or1(global_scheme);

    ASSERT_EMPTY_OP_IN_STACK;
}

static void test_op_not_case1() {
    global_scheme->op = cell_op_not;
    global_scheme->args = LIST_1(G_TRUE);

    ASSERT_OP_CURRENT(not);
    op_not(global_scheme);
    assert_cell_equal(global_scheme->returnValue, G_FALSE);

    ASSERT_EMPTY_OP_IN_STACK;
}

static void test_op_not_case2() {
    global_scheme->op = cell_op_not;
    global_scheme->args = LIST_1(G_FALSE);

    ASSERT_OP_CURRENT(not);
    op_not(global_scheme);
    assert_cell_equal(global_scheme->returnValue, G_TRUE);

    ASSERT_EMPTY_OP_IN_STACK;
}

int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_op_and_case1),
            cmocka_unit_test(test_op_and_case2),
            cmocka_unit_test(test_op_and_case3),
            cmocka_unit_test(test_op_and_case4),
            cmocka_unit_test(test_op_or_case1),
            cmocka_unit_test(test_op_or_case2),
            cmocka_unit_test(test_op_or_case3),
            cmocka_unit_test(test_op_or_case4),
            cmocka_unit_test(test_op_not_case1),
            cmocka_unit_test(test_op_not_case2),
    };
    return cmocka_run_group_tests(tests, setup_scheme, teardown_scheme);
}
